﻿#include "FaceAction.h"

FaceAction::FaceAction(SeetaImageData& imgData, SeetaRect& fRect, std::string modelpath) {
	init_ImageData(imgData, fRect);
	contructContent(modelpath);
}
FaceAction::FaceAction(cv::Mat& imgMat, SeetaRect& fRect, std::string modelpath) {
	init_Mat(imgMat, fRect);
	contructContent(modelpath);
}
void FaceAction::init_ImageData(SeetaImageData& imgData, SeetaRect& fRect) {
	this->imgData = &imgData;
	cv::Mat mat(imgData.height, imgData.width, CV_8UC3, imgData.data);
	this->imgMat = mat;
	cv::cvtColor(mat.clone(), imgMat_gray, cv::COLOR_BGR2GRAY);
	this->imgData_gray = new SeetaImageData();
	this->imgData_gray->data = imgMat_gray.data;
	this->imgData_gray->channels = imgMat_gray.channels();
	this->imgData_gray->width = imgMat_gray.cols;
	this->imgData_gray->height = imgMat_gray.rows;
	this->fRect = &fRect;
}

void FaceAction::init_Mat(cv::Mat& imgMat, SeetaRect& fRect) {

	cv::Mat mat(imgMat);
	this->imgMat = mat;
	cv::cvtColor(mat.clone(), imgMat_gray, cv::COLOR_BGR2GRAY);
	this->imgData = new SeetaImageData();
	this->imgData->data = imgMat.data;
	this->imgData->channels = imgMat.channels();
	this->imgData->width = imgMat.cols;
	this->imgData->height = imgMat.rows;
	this->imgData_gray = new SeetaImageData();
	this->imgData_gray->data = imgMat_gray.data;
	this->imgData_gray->channels = imgMat_gray.channels();
	this->imgData_gray->width = imgMat_gray.cols;
	this->imgData_gray->height = imgMat_gray.rows;
	this->fRect = &fRect;
}

void FaceAction::contructContent(seeta::FaceLandmarker* flm68, 
	seeta::FaceLandmarker* flm5, seeta::EyeStateDetector* ESD, 
	seeta::FaceDetector* FD, seeta::QualityOfPoseEx* QP) {
    this->flm68 = flm68;
    this->flm5 = flm5;
//	this->ESD = ESD;
    this->FD = FD;
    this->QP = QP;
}

seeta::QualityOfPoseEx* FaceAction::getQualityOfPoseEx(const seeta::ModelSetting& setQP) {
    return new seeta::QualityOfPoseEx(setQP);
}

seeta::FaceDetector* FaceAction::getFaceDetector(const seeta::ModelSetting& setFD) {
    return new seeta::FaceDetector(setFD);
}

seeta::FaceLandmarker* FaceAction::getFaceLandmarker68(const seeta::ModelSetting& s68) {
    return new seeta::FaceLandmarker(s68);
}

seeta::FaceLandmarker* FaceAction::getFaceLandmarker5(const seeta::ModelSetting& s5) {
    return new seeta::FaceLandmarker(s5);
}

//seeta::EyeStateDetector* FaceAction::getEyeStateDetector(string modelpath) {
//	seeta::ModelSetting se;
//	se.set_id(0);
//	se.append(modelpath + "eye_state.csta");
//	seeta::EyeStateDetector* ESD = new seeta::EyeStateDetector(se);
//	return ESD;
//}


void FaceAction::contructContent(const std::string modelpath) {
    this->modelpath = modelpath;
    seeta::ModelSetting s68;
    s68.set_id(0);
    s68.append(modelpath + "face_landmarker_pts68.csta");
    this->flm68 = new seeta::FaceLandmarker(s68);
    seeta::ModelSetting s5;
    s5.set_id(0);
    s5.append(modelpath + "face_landmarker_pts5.csta");
    this->flm5 = new seeta::FaceLandmarker(s5);
//	seeta::ModelSetting se;
//	se.set_id(0);
//	se.append(modelpath + "eye_state.csta");
//    //this->ESD = new seeta::EyeStateDetector(se);
    seeta::ModelSetting setFD;
    setFD.set_id(0);
    setFD.append(modelpath + "face_detector.csta");
    this->FD = new seeta::FaceDetector(setFD);
    seeta::ModelSetting setQP;
    setQP.set_id(0);
    setQP.append(modelpath + "pose_estimation.csta");
    this->QP = new seeta::QualityOfPoseEx(setQP);
}

bool FaceAction :: init_points() {
	SeetaPointF pts[5];
	for (int m = 0; m < 5; m++) {
		pts[m].x = this->points5->at(m).x;
		pts[m].y = this->points5->at(m).y;
	}
	checkRes = this->QP->check(*this->imgData, *this->fRect, pts, -1);
	if (checkRes.score < 0.8 && checkRes.score < 0.9) {
		std::cout << "��ʼ��ʧ�ܣ�����������ͷ����" << checkRes.score << std::endl;
		return false;
	}
	this->i_points5 = this->points5;
	this->i_points68 = this->points68;
	INIT_TURNUP_ANGLE = calcAngle(0, 30, 4);
	INIT_TURNLEFT_ANGLE = calcAngle(16, 30, 12);
	INIT_TURNRIGHT_ANGLE = calcAngle(36, 30, 45);
	INIT = 1;
	return true;
}

bool FaceAction::init_points(std::vector<SeetaPointF>& i_points5, std::vector<SeetaPointF>& i_points68) {
	
	if (i_points5.empty() || i_points68.empty()) {
		std::cout << "points is empty!" << std::endl;
	}
	else{
		SeetaPointF pts[5];
		for (int m = 0; m < 5; m++) {
			pts[m].x = this->points5->at(m).x;
			pts[m].y = this->points5->at(m).y;
		}
		checkRes = this->QP->check(*this->imgData, *this->fRect, pts, -1);
		if (checkRes.score < 0.8 && checkRes.score < 0.9) {
			std::cout << "��ʼ��ʧ�ܣ�����������ͷ����" << checkRes.score << std::endl;
			return false;
		}
		this->i_points5 = this->points5;
		this->i_points68 = this->points68;
		INIT_TURNUP_ANGLE = calcAngle(0, 30, 4);
		INIT_TURNLEFT_ANGLE = calcAngle(16, 30, 12);
		INIT_TURNRIGHT_ANGLE = calcAngle(36, 30, 45);
	}
	INIT = 1;
	return true;
}

void FaceAction::setPoints(std::vector<SeetaPointF>& points) {
	if (points.empty()) {
		std::cout << "points is empty!" << std::endl;
	}
	else if (points.size() == 5) {
		this->points5 = &points;
	}
	else {
		this->points68 = &points;
	}
}

void FaceAction::resetAction() {
	EYE_ROTATION_LEFT = 0;
	EYE_ROTATION_RIGHT = 0;
	TURN_LEFT = 0;
	TURN_RIGHT = 0;
	TURN_DOWN = 0;
	TURN_UP = 0;
	LEFT_BLINK = 0;
	RIGHT_BLINK = 0;
	ALL_BLINK = 0;
	OPEN_MOUTH = 0;
}

int FaceAction::distance(int d1, int d2) {
	double x1 = this->points68->at(d1).x;
	double y1 = this->points68->at(d1).y;
	double x2 = this->points68->at(d2).x;
	double y2 = this->points68->at(d2).y;
	return int(sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
}

int FaceAction::calcAngle(int d1, int d2, int d3) {
	/*
	d1:��һ���˵㣻
	d2:�м䶥�㣻
	d3:�ڶ����˵㣻
	*/
	double x1 = this->points68->at(d1).x;
	double y1 = this->points68->at(d1).y;
	double x2 = this->points68->at(d2).x;
	double y2 = this->points68->at(d2).y;
	double x3 = this->points68->at(d3).x;
	double y3 = this->points68->at(d3).y;
	double numerator = (x1 - x2) * (x3 - x2) + (y3 - y2) * (y1 - y2);
	double denumerator = sqrt(((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) * ((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2)));
	//std::cout << "���� ��" << numerator << ",��ĸ ��" << denumerator << std::endl;
	return int(std::acos(numerator / denumerator) * 180 / 3.1415926);
}

int FaceAction::checkMouth() {
	if (distance(61, 67) <= 10 && distance(62, 66) < 10 && distance(63, 65) < 10 && OPEN_MOUTH != 1) {
		if (OPEN_MOUTH == 0) OPEN_MOUTH = 1;
		if (OPEN_MOUTH == 2) {
			OPEN_MOUTH = 3;
			std::cout << "�������һ�����춯�� " << std::endl;
			resetAction();
			return 7;
		}
	}
	if (distance(61, 67) > 20 && distance(62, 66) > 20 && distance(63, 65) > 20) {
		OPEN_MOUTH = 2;
	}
	return 0;
}

int FaceAction::checkTurn(int turnType) {
	/*
	��ƫͷ��Ӧ�Ƕȣ�0_30_4��
	��ƫͷ��Ӧ�Ƕȣ�16_30_12��
	��ƫͷ��Ӧ�Ƕȣ�36_30_45��
	*/
	int angle;
	switch (turnType)
	{
	case 4:
		angle = calcAngle(0, 30, 4);
		if (abs(angle - INIT_TURNLEFT_ANGLE) < 20 && TURN_LEFT != 1) {
			if (TURN_LEFT == 0) TURN_LEFT = 1;
			if (TURN_LEFT == 2) {
				TURN_LEFT = 3;
				std::cout << "�������һ����ƫͷ���� " << std::endl;
				resetAction();
				return TURN_LEFT_ACTION;
			}
		}
		if (angle - INIT_TURNLEFT_ANGLE > 40 && TURN_LEFT == 1) {
			TURN_LEFT = 2;
		}
		break;
	case 5:
		angle = calcAngle(16, 30, 12);
		if (abs(angle - INIT_TURNRIGHT_ANGLE) < 20 && TURN_RIGHT != 1) {
			if (TURN_RIGHT == 0) TURN_RIGHT = 1;
			if (TURN_RIGHT == 2) {
				TURN_RIGHT = 3;
				std::cout << "�������һ����ƫͷ���� " << std::endl;
				resetAction();
				return TURN_RIGHT_ACTION;
			}
		}
		if (angle - INIT_TURNRIGHT_ANGLE > 40 && TURN_RIGHT == 1) {
			TURN_RIGHT = 2;
		}
		break;
	case 6:
		angle = calcAngle(17, 33, 26);
		UP_FRAMES++;
		if (abs(angle - INIT_TURNUP_ANGLE) < 20 && TURN_UP != 1) {
			if (TURN_UP == 0) {
				UP_FRAMES = 0;
				TURN_UP = 1;
			}
			if (TURN_UP == 2) {
				if (UP_FRAMES < 10) {
					std::cout << "�붯����һ�㣡 " << std::endl;
					TURN_UP = 1;
					UP_FRAMES = 0;
					return 0;
				}
				else {
					TURN_UP = 3;
					std::cout << "�������һ����ƫͷ���� " << UP_FRAMES << std::endl;
					UP_FRAMES = 0;
					resetAction();
				}
				return TURN_UP_ACTION;
			}
		}
		if (angle - INIT_TURNUP_ANGLE > 25 && TURN_UP == 1) {
			TURN_UP = 2;
		}
		break;
	default:
		break;
	}
	return 0;
}

int FaceAction::checkAllTurn() {
	int UP_RES = checkTurn(TURN_UP_ACTION);
	int LEFT_RES = checkTurn(TURN_LEFT_ACTION);
	int RIGHT_RES = checkTurn(TURN_RIGHT_ACTION);
	if (LEFT_RES == TURN_LEFT_ACTION)return TURN_LEFT_ACTION;
	if (RIGHT_RES == TURN_RIGHT_ACTION) return TURN_RIGHT_ACTION;
	if (UP_RES == TURN_UP_ACTION) return TURN_UP_ACTION;
	return 0;
}

void FaceAction::setPoints68() {

	this->points68 = new std::vector<SeetaPointF>(flm68->mark(*this->imgData_gray, *this->fRect));
}

void FaceAction::setPoints5() {
	this->points5 = new std::vector<SeetaPointF>(flm5->mark(*this->imgData_gray, *this->fRect));
}

cv::Mat FaceAction::drawPoints(int pointsSize, bool showNumber) {
	std::vector<SeetaPointF> points;
	if (pointsSize == 5) {
		this->setPoints5();
		points = *this->points5;
	}
	else {
		this->setPoints68();
		points = *this->points68;
	}
	int i = 0;
	cv::Mat resMat = (this->imgMat).clone();
	for (auto point : points) {
		if (showNumber) {
			cv::putText(resMat, std::to_string(i), cv::Point(point.x, point.y), cv::FONT_HERSHEY_COMPLEX, 0.5, CV_RGB(255, 0, 242), 1);
		}
		cv::circle(resMat, cv::Point(point.x, point.y), 2, (0, 0, 0), 2);
		i++;
	}
	return resMat;
}

cv::Mat FaceAction::drawPoints(cv::Mat& img, bool showNumber, int pointsSize) {
    SeetaImageData imgData;
    SeetaRect face;
    SeetaFaceInfoArray face_array;
    cv::Mat resMat = img.clone();

    imgData.data = resMat.data;
    imgData.width = resMat.cols;
    imgData.height = resMat.rows;
    imgData.channels = resMat.channels();
    face_array = this->FD->detect(imgData);
    for (int i = 0; i < face_array.size; i++) {
        face = face_array.data[i].pos;
        this->init_Mat(resMat, face);
    }
    if (face_array.size > 0) {
        std::vector<SeetaPointF> points;
        if (pointsSize == 5) {
            this->setPoints5();
            points = *this->points5;
        }
        else {
            this->setPoints68();
            points = *this->points68;
        }
        int i = 0;
        for (auto point : points) {
            if (showNumber) {
                cv::putText(resMat, std::to_string(i), cv::Point(point.x, point.y),
                    cv::FONT_HERSHEY_COMPLEX, 0.5, CV_RGB(0, 255, 0), 1);
            }
            cv::circle(resMat, cv::Point(point.x, point.y), 1.5, CV_RGB(255, 255, 255), 2);
            i++;
        }
    }
    return resMat;
}

EYESTATE_PAIR FaceAction::getEyestate() {
	SeetaPointF pts[5];
	for (int m = 0; m < 5; m++) {
		pts[m].x = this->points5->at(m).x;
		pts[m].y = this->points5->at(m).y;
	}
	checkRes = this->QP->check(*this->imgData, *this->fRect, pts, -1);
	seeta::EyeStateDetector::EYE_STATE leftstate, rightstate;
    //this->ESD->Detect(*this->imgData, pts, leftstate, rightstate);
	return EYESTATE_PAIR(leftstate, rightstate);
}

int FaceAction::checkEyes(seeta::EyeStateDetector::EYE_STATE leftstate,
	seeta::EyeStateDetector::EYE_STATE rightstate, int eyeType) {
	std::map<seeta::EyeStateDetector::EYE_STATE, std::string> eyeStates;
    eyeStates[seeta::EyeStateDetector::EYE_CLOSE] = "���� ";
    eyeStates[seeta::EyeStateDetector::EYE_OPEN] = "���� ";
    eyeStates[seeta::EyeStateDetector::EYE_RANDOM] = "��� ";
    eyeStates[seeta::EyeStateDetector::EYE_UNKNOWN] = "��ȷ�� ";
	if (LEFT_BLINK == 0 && RIGHT_BLINK == 0 && ALL_BLINK == 0 && 
		(leftstate == seeta::EyeStateDetector::EYE_UNKNOWN || rightstate == seeta::EyeStateDetector::EYE_UNKNOWN)) {
		LEFT_BLINK = 0;
		RIGHT_BLINK = 0;
		ALL_BLINK = 0;
	}
	switch (eyeType) {
	case 1:
		if (leftstate == seeta::EyeStateDetector::EYE_OPEN && rightstate == seeta::EyeStateDetector::EYE_OPEN)
		{
			if (LEFT_BLINK == 0) LEFT_BLINK = 1;
			if (LEFT_BLINK == 2) LEFT_BLINK = 3;
		}
		if (leftstate == seeta::EyeStateDetector::EYE_CLOSE 
			&& rightstate == seeta::EyeStateDetector::EYE_OPEN 
			&& LEFT_BLINK == 1)  LEFT_BLINK = 2;
		if (LEFT_BLINK == 3) {
			std::cout << "��գ������" << std::endl;
			resetAction();
			return EYE_LEFT_BLINK_ACTION;
		}break;
	case 2:
		if (leftstate == seeta::EyeStateDetector::EYE_OPEN && rightstate == seeta::EyeStateDetector::EYE_OPEN)
		{
			if (RIGHT_BLINK == 0) RIGHT_BLINK = 1;
			if (RIGHT_BLINK == 2) RIGHT_BLINK = 3;
		}
		if (leftstate == seeta::EyeStateDetector::EYE_OPEN
			&& rightstate == seeta::EyeStateDetector::EYE_CLOSE
			&& RIGHT_BLINK == 1)  RIGHT_BLINK = 2;
		if (RIGHT_BLINK == 3) {
			std::cout << "��գ������" << std::endl;
			resetAction();
			return EYE_RIGHT_BLINK_ACTION;
		}
		break;
	case 3:
		if (leftstate == seeta::EyeStateDetector::EYE_OPEN && rightstate == seeta::EyeStateDetector::EYE_OPEN)
		{
			if (ALL_BLINK == 0) ALL_BLINK = 1;
			if (ALL_BLINK == 2) ALL_BLINK = 3;
		}
		if (leftstate == seeta::EyeStateDetector::EYE_CLOSE
			&& rightstate == seeta::EyeStateDetector::EYE_CLOSE
			&& ALL_BLINK == 1)  ALL_BLINK = 2;
		if (ALL_BLINK == 3) {
			std::cout << "��գ��˫��" << std::endl;
			resetAction();
			return EYE_ALL_BLINK_ACTION;
		}break;
	default:
		break;
	}
	//std::cout << "����״̬��" << eyeStates[leftstate] << "����״̬��" << eyeStates[rightstate] << std::endl;
	return 0;
}

int FaceAction::checkEyes(int eyeType) {
	EYESTATE_PAIR pair = getEyestate();
	seeta::EyeStateDetector::EYE_STATE leftstate = pair.first;
	seeta::EyeStateDetector::EYE_STATE rightstate = pair.second;
	std::map<seeta::EyeStateDetector::EYE_STATE, std::string> eyeStates;
    eyeStates[seeta::EyeStateDetector::EYE_CLOSE] = "���� ";
    eyeStates[seeta::EyeStateDetector::EYE_OPEN] = "���� ";
    eyeStates[seeta::EyeStateDetector::EYE_RANDOM] = "��� ";
    eyeStates[seeta::EyeStateDetector::EYE_UNKNOWN] = "��ȷ�� ";
	if (LEFT_BLINK == 0 && RIGHT_BLINK == 0 && ALL_BLINK == 0 &&
		(leftstate == seeta::EyeStateDetector::EYE_UNKNOWN || rightstate == seeta::EyeStateDetector::EYE_UNKNOWN)) {
		LEFT_BLINK = 0;
		RIGHT_BLINK = 0;
		ALL_BLINK = 0;
	}
	switch (eyeType) {
	case 1:
		if (leftstate == seeta::EyeStateDetector::EYE_OPEN && rightstate == seeta::EyeStateDetector::EYE_OPEN)
		{
			if (LEFT_BLINK == 0) LEFT_BLINK = 1;
			if (LEFT_BLINK == 2) LEFT_BLINK = 3;
		}
		if (leftstate == seeta::EyeStateDetector::EYE_CLOSE
			&& rightstate == seeta::EyeStateDetector::EYE_OPEN
			&& LEFT_BLINK == 1)  LEFT_BLINK = 2;
		if (LEFT_BLINK == 3) {
			std::cout << "��գ������" << std::endl;
			resetAction();
			return EYE_LEFT_BLINK_ACTION;
		}break;
	case 2:
		if (leftstate == seeta::EyeStateDetector::EYE_OPEN && rightstate == seeta::EyeStateDetector::EYE_OPEN)
		{
			if (RIGHT_BLINK == 0) RIGHT_BLINK = 1;
			if (RIGHT_BLINK == 2) RIGHT_BLINK = 3;
		}
		if (leftstate == seeta::EyeStateDetector::EYE_OPEN
			&& rightstate == seeta::EyeStateDetector::EYE_CLOSE
			&& RIGHT_BLINK == 1)  RIGHT_BLINK = 2;
		if (RIGHT_BLINK == 3) {
			std::cout << "��գ������" << std::endl;
			resetAction();
			return EYE_RIGHT_BLINK_ACTION;
		}
		break;
	case 3:
		if (leftstate == seeta::EyeStateDetector::EYE_OPEN && rightstate == seeta::EyeStateDetector::EYE_OPEN)
		{
			if (ALL_BLINK == 0) ALL_BLINK = 1;
			if (ALL_BLINK == 2) ALL_BLINK = 3;
		}
		if (leftstate == seeta::EyeStateDetector::EYE_CLOSE
			&& rightstate == seeta::EyeStateDetector::EYE_CLOSE
			&& ALL_BLINK == 1)  ALL_BLINK = 2;
		if (ALL_BLINK == 3) {
			std::cout << "��գ��˫��" << std::endl;
			resetAction();
			return EYE_ALL_BLINK_ACTION;
		}break;
	default:
		break;
	}
	//std::cout << "����״̬��" << eyeStates[leftstate] << "����״̬��" << eyeStates[rightstate] << std::endl;
	return 0;
}

int FaceAction::checkAllEyes() {
	EYESTATE_PAIR pair = getEyestate();
	if (checkRes.score < 0.8 && checkRes.score < 0.9) {
		std::cout << "�޷����գ�۶���������������ͷ�� " << std::endl;
		LEFT_BLINK = 0;
		RIGHT_BLINK = 0;
		ALL_BLINK = 0;
	}
	int LEFT_RES = checkEyes(pair.first, pair.second, EYE_LEFT_BLINK_ACTION);
	int ALL_RES = checkEyes(pair.first, pair.second, EYE_ALL_BLINK_ACTION);
	int RIGHT_RES = checkEyes(pair.first, pair.second, EYE_RIGHT_BLINK_ACTION);
	if (LEFT_RES == EYE_LEFT_BLINK_ACTION) return EYE_LEFT_BLINK_ACTION;
	if (RIGHT_RES == EYE_RIGHT_BLINK_ACTION) return EYE_RIGHT_BLINK_ACTION;
	if (ALL_RES == EYE_ALL_BLINK_ACTION)return EYE_ALL_BLINK_ACTION;
	return 0;
}

int FaceAction::checkAllAction() {
	int TURN_RES = checkAllTurn();
	int EYE_RES = checkAllEyes();
	int MOUTH_RES = checkMouth();
	if (MOUTH_RES != 0) return MOUTH_ACTION;
	if (EYE_RES != 0) return EYE_RES;
	if (TURN_RES != 0) return TURN_RES;
	return 0;
}

cv::Mat FaceAction::getEyeFrame(int eye) {
	std::vector<cv::Point> pts;
	if (eye == LEFT) {
		std::vector<int> ids({ 36, 37, 38, 39, 40, 41 });
		for (int i = 0; i < 6; ++i) {
			cv::Point p;
			p.x = points68->at(ids[i]).x;
			p.y = points68->at(ids[i]).y;
			pts.push_back(p);
		}
	}
	else {
		std::vector<int> ids({42, 43, 44, 45, 46, 47});
		for (int i = 0; i < 6; ++i) {
			cv::Point p;
			p.x = points68->at(ids[i]).x;
			p.y = points68->at(ids[i]).y;
			pts.push_back(p);
		}
	}
	int x_max = 0, x_min = 100000, y_max = 0, y_min = 100000;
	for (auto point : pts) {
		if (x_max <= point.x) x_max = point.x;
		if (x_min >= point.x) x_min = point.x;
		if (y_max <= point.y) y_max = point.y;
		if (y_min >= point.y) y_min = point.y;
	}
	int margin = 5;
	x_max = (margin + x_max) < imgMat_gray.cols ? margin + x_max : imgMat_gray.cols - 1;
	x_min = (x_min - margin) >= 0 ? x_min - margin : 0; 
	y_max = (margin + y_max) < imgMat_gray.rows ? margin + y_max : imgMat_gray.rows - 1;
	y_min = (y_min - margin) >= 0 ? y_min - margin : 0;
	int width = x_max - x_min, height = y_max - y_min;
	cv::Mat imgMask = cv::Mat(cv::Size(this->imgMat_gray.cols, this->imgMat_gray.rows), CV_8UC1);
	cv::fillPoly(imgMask, pts, CV_RGB(0, 0, 0));
	cv::Mat black_frame(cv::Size(this->imgMat_gray.cols, this->imgMat_gray.rows), CV_8UC1);
	cv::bitwise_not(this->imgMat_gray.clone(), black_frame, imgMask);
	cv::Mat eyeFrame = imgMat_gray.clone()(cv::Range(y_min, y_max), cv::Range(x_min, x_max));

	if (eye == LEFT) {
		LEye_InitCenter.x = width / 2;
		LEye_InitCenter.y = height / 2;
		EFrame_left = eyeFrame;
		LEye_Center.x = x_min;
		LEye_Center.y = y_min;
	}
	else {
		REye_InitCenter.x = width / 2;
		REye_InitCenter.y = height / 2;
		EFrame_right = eyeFrame;
		REye_Center.x = x_min;
		REye_Center.y = y_min;
	}
	//cv::Mat eyeFrame_gray = eyeFrame.clone();
	//cv::cvtColor(eyeFrame, eyeFrame_gray, cv::COLOR_BGR2GRAY);
	return eyeFrame.clone();
}

cv::Mat FaceAction::getIrisFrame(cv::Mat& eye_frame, int threshould) {
	cv::Mat m1;
	cv::bilateralFilter(eye_frame, m1, 10, 15, 15);
	cv::Mat m2;
	//std::vector<std::vector<float>> kernel({ {1, 1, 1}, {1, 1, 1}, {1, 1, 1} });
	//cv::Mat kernel = cv::Mat::ones(cv::Size(3, 3), CV_8UC1);
	//cv::erode(m1, m2, kernel, cv::Point(-1, -1), 3);
	cv::erode(m1, m2, cv::Mat(), cv::Point(-1, -1), 3);
	cv::Mat m3;
	cv::threshold(m2, m3, threshould, 255, cv::THRESH_BINARY);
	//cv::cvtColor(m2, m2, cv::COLOR_BGR2GRAY);
	return m3;
}

float FaceAction::getIrisSize(cv::Mat iris_frame) {
	cv::Mat frame = iris_frame(cv::Range(5, iris_frame.rows), cv::Range(5, iris_frame.cols));
	int height = frame.rows;
	int width = frame.cols;
	float nb_pixels = height * width;
	float nb_blacks = nb_pixels - cv::countNonZero(frame);
	return nb_blacks / nb_pixels;
}

int FaceAction::getBestThreshould(cv::Mat eye_frame) {
	std::map<int, float> trials;
	float average_iris_size = 0.3;
	float iris_size = 0;
	int best_threshould = 10;
	
	for (int t = 10; t < 100; t += 5) {
		auto i = getIrisSize(getIrisFrame(eye_frame, t));
		if (abs(iris_size - average_iris_size) >= abs(i - average_iris_size)) {
			iris_size = i;
			best_threshould = t;
		}
		trials[t] = i;
		
	}
	return best_threshould;
}

void FaceAction::getEyeCenter() {
	getEyeFrame(LEFT);
	getEyeFrame(RIGHT);
	auto leftThresh = getBestThreshould(EFrame_left);
	auto rightThresh = getBestThreshould(EFrame_right);
	auto leftIris = getIrisFrame(EFrame_left, leftThresh);
	auto rightIris = getIrisFrame(EFrame_right, rightThresh);
	//cv::imshow("left eye", EFrame_right);
	//cv::imshow("left iris", rightIris);

	std::vector<std::vector<cv::Point> > LContours;
	std::vector<std::vector<cv::Point> > RContours;
	cv::findContours(leftIris, LContours, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
	cv::findContours(rightIris, RContours, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
	float area = 100000;
	std::vector<cv::Point> LContour;
	std::vector<cv::Point> RContour;
	for (auto lcontour : LContours) {
		auto a = cv::contourArea(lcontour);
		if (area >= a) {
			area = a;
			LContour = lcontour;
		}
	}
	area = 100000;
	for (auto rcontour : RContours) {
		auto a = cv::contourArea(rcontour);
		if (area >= a) {
			area = a;
			RContour = rcontour;
		}
	}
	auto LMoments = cv::moments(LContour, false);
	LEye_RltCenter.x = int(LMoments.m10 / LMoments.m00); 
	LEye_RltCenter.y = int(LMoments.m01 / LMoments.m00);
	LEye_Center.x += int(LMoments.m10 / LMoments.m00);
	LEye_Center.y += int(LMoments.m01 / LMoments.m00); 
	auto RMoments = cv::moments(RContour, false);
	REye_RltCenter.x = int(RMoments.m10 / RMoments.m00);
	REye_RltCenter.y = int(RMoments.m01 / RMoments.m00);
	REye_Center.x += int(RMoments.m10 / RMoments.m00);
	REye_Center.y += int(RMoments.m01 / RMoments.m00);
	//cv::Mat showContours = EFrame_left.clone();
	//cv::drawContours(showContours, LContours, -1, CV_RGB(0, 255, 0), 1);
	//cv::circle(showContours, cv::Point(int(LMoments.m10 / LMoments.m00), int(LMoments.m01 / LMoments.m00)), 2, CV_RGB(255, 255, 255));
	//cv::imshow("leftContours", showContours);
}

int FaceAction::checkEyeRotation() {
	getEyeCenter();
	float LEyeWidth = EFrame_left.cols;
	float REyeWidth = EFrame_right.cols;
	if ((LEye_RltCenter.x / LEyeWidth) <= 0.33
		&& (REye_RltCenter.x / REyeWidth) <= 0.33
		&& (EYE_ROTATION_LEFT == 1))
		EYE_ROTATION_LEFT = 2;
	if ((LEye_RltCenter.x / LEyeWidth) > 0.33
		&& (LEye_RltCenter.x / LEyeWidth) < 0.66
		&& (REye_RltCenter.x / REyeWidth) > 0.33
		&& (REye_RltCenter.x / REyeWidth) < 0.66) {
		if (EYE_ROTATION_LEFT == 0) EYE_ROTATION_LEFT = 1;
		if (EYE_ROTATION_LEFT == 2) {
			EYE_ROTATION_LEFT = 3;
			std::cout << "���������ƶ���" << std::endl;
			resetAction();
			return EYE_ROTATION_LEFT_ACTION;
		}
		if (EYE_ROTATION_RIGHT == 0) EYE_ROTATION_RIGHT = 1;
		if (EYE_ROTATION_RIGHT == 2) {
			EYE_ROTATION_RIGHT = 3;
			std::cout << "���������ƶ���" << std::endl;
			resetAction();
			return EYE_ROTATION_RIGHT_ACTION;
		}
	}
	if ((LEye_RltCenter.x / LEyeWidth) >= 0.66
		&& (REye_RltCenter.x / REyeWidth) >= 0.66
		&& EYE_ROTATION_RIGHT == 1)
		EYE_ROTATION_RIGHT = 2;
	return 0;
}

cv::Mat FaceAction::showEyeCenter(cv::Mat& mat) {
	getEyeCenter();
	cv::circle(mat, LEye_Center, 2, CV_RGB(0, 255, 0), -1);
	cv::circle(mat, REye_Center, 2, CV_RGB(0, 255, 0), -1);
	return mat;
}

int FaceAction::inferAction(cv::Mat& img) {
	SeetaImageData imgData;
	SeetaRect face;
	SeetaFaceInfoArray face_array;
	cv::Mat frame = img.clone();

	//��תͼ��ʹ֮����ʵ������ͬ
    //cv::flip(frame, frame, 1);
	imgData.data = frame.data;
	imgData.width = frame.cols;
	imgData.height = frame.rows;
	imgData.channels = frame.channels();
	face_array = this->FD->detect(imgData);

	/*���ֵ��Ĭ��Ϊ0��Ϊ0ʱ��ʾ�޶���
	��Ӧ�沿�������ͣ�
	const int EYE_LEFT_BLINK_ACTION = 1;
	const int EYE_RIGHT_BLINK_ACTION = 2;
	const int EYE_ALL_BLINK_ACTION = 3;
	const int TURN_LEFT_ACTION = 4;
	const int TURN_RIGHT_ACTION = 5;
	const int TURN_UP_ACTION = 6;
	const int MOUTH_ACTION = 7;
	*/
	int res = 0;
	for (int i = 0; i < face_array.size; i++) {
		face = face_array.data[i].pos;
		this->init_Mat(frame, face);
		this->setPoints68();
		this->setPoints5();
		if (this->INIT == 1) {
			res = this->checkAllAction();
		}
	}
	if (face_array.size == 1) {
		if (this->INIT == 0) {
			if (this->init_points())
				std::cout << "�ɹ���ʼ��fa" << this->checkRes.score << std::endl;
		}
	}
	return res;
}

int FaceAction::inferEyeRotate(cv::Mat& img) {
	SeetaImageData imgData;
	SeetaRect face;
	SeetaFaceInfoArray face_array;
	cv::Mat frame = img.clone(), canvas;

	//��תͼ��ʹ֮����ʵ������ͬ
    //cv::flip(frame, frame, 1);
	canvas = frame.clone();
	imgData.data = frame.data;
	imgData.width = frame.cols;
	imgData.height = frame.rows;
	imgData.channels = frame.channels();
	face_array = this->FD->detect(imgData);

	//���ֵ��Ĭ��Ϊ0��Ϊ0ʱ��ʾ����û����Ϊ8ʱ��ʾ�������ƶ���Ϊ9ʱ��ʾ�������ƶ�
	int res = 0;
	for (int i = 0; i < face_array.size; i++) {
		face = face_array.data[i].pos;
		this->init_Mat(canvas, face);
		this->setPoints68();
		this->setPoints5();
		//����׷��
		res = this->checkEyeRotation();
		//ֻ���һ������
		break;
	}
	return res;
}
